<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据解析</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Roboto', sans-serif;
            background-color: #f0f2f5;
            color: #333;
            line-height: 1.6;
        }

        .wrapper {
            display: flex;
            flex-direction: column;
            min-height: 100vh;
            padding: 20px;
            background: linear-gradient(135deg, #667eea, #764ba2);
        }

        .header {
            background-color: #fff;
            color: #333;
            padding: 10px;
            text-align: center;
            border-radius: 10px;
            margin-bottom: 20px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        .header h1 {
            font-size: 2rem;
            font-weight: bold;
        }

        .header p {
            font-size: 1rem;
            margin-top: 5px;
        }

        .content {
            flex: 1;
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
        }

        .content-left,
        .content-right {
            flex: 1;
            min-width: 300px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            padding: 20px;
            transition: transform 0.3s ease;
        }

        .content-left:hover,
        .content-right:hover {
            transform: translateY(-5px);
        }

        .card {
            /* margin-bottom: 20px; */
        }

        .card-content {
            padding: 20px 20px 20px 0;
        }

        .card-title {
            font-size: 1.8rem;
            font-weight: bold;
            margin-bottom: 10px;
            position: relative;
        }

        .card-title:before {
            content: '';
            position: absolute;
            bottom: -5px;
            left: 0;
            width: 60px;
            height: 4px;
            background: linear-gradient(135deg, #667eea, #764ba2);
        }

        .card-description {
            font-size: 1rem;
            line-height: 1.6;
        }

        .input-box {
            width: 100%;
            height: 60px;
            padding: 10px;
            border: 1px solid #ced4da;
            border-radius: 5px;
            font-size: 1rem;
            margin-bottom: 10px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }

        .input-box:focus {
            border-color: #667eea;
            box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, .25);
            outline: none;
        }

        .send-button {
            display: inline-block;
            padding: 10px 20px;
            background-color: #667eea;
            color: #fff;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 1rem;
            transition: background-color 0.3s ease;
        }

        .send-button:hover {
            background-color: #556cd6;
        }

        .send-button-width {
            width: 100%;
        }

        ul {
            list-style-type: none;
            padding: 0;
        }

        li {
            border: 1px solid #ced4da;
            padding: 10px;
            margin-bottom: 10px;
            border-radius: 5px;
            background-color: #f8f9fa;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        }

        li:nth-child(5),
        li:nth-child(6),
        li:nth-child(7) {
            color: #667eea;
        }

        li:last-child {
            margin-bottom: 0;
        }

        @media (max-width: 768px) {
            .content {
                flex-direction: column;
            }
        }
    </style>
</head>

<body>
    <div class="wrapper">
        <header class="header">
            <h1>设备与平台通信数据解析工具</h1>
        </header>
        <main class="content">
            <div class="content-left">
                <div class="card">
                    <div class="card-content" style="text-align: left;">
                        <p class="card-description"></p>
                        <ul id="loopList"></ul>
                    </div>
                </div>
                <footer class="footer">
                    <textarea id="input1-box" class="input-box" placeholder="请输入内容"></textarea>
                    <button id="btn" class="send-button send-button-width">解析原始数据</button>
                </footer>
            </div>
            <div class="content-right">
                <div style="display: flex; align-items: center;">
                    <textarea id="input-box3" class="input-box" placeholder="请输入内容"></textarea>
                    <span style="margin: 0 10px;">➡️</span>
                    <div id="input-box3-text" class="input-box"></div>
                </div>
                <button id="btn-to-ascii" class="send-button send-button-width" style="margin-bottom: 20px;">转字符串</button>
                <div style="display: flex; align-items: center;">
                    <textarea id="input-box2" class="input-box" placeholder="请输入内容"></textarea>
                    <span style="margin: 0 10px;">➡️</span>
                    <div id="input-box2-text" class="input-box"></div>
                </div>
                <button id="btn-to-dec" class="send-button send-button-width">转十进制</button>
            </div>
        </main>
    </div>
    <script>
        window.onload = () => {
            onInit();
        }

        const onInit = () => {
            const packetData = [
                { id: 0, label: '起始字节', value: '', byte: 1, po: 4 },
                { id: 1, label: '报文长度', value: '', byte: 2, po: 4 },
                { id: 2, label: '服务器序号', value: '', byte: 2, po: 4 },
                { id: 3, label: '设备序号', value: '', byte: 2, po: 4 },
                { id: 4, label: '设备号', value: '', byte: 11, po: 22 },
                { id: 5, label: '功能码', value: '', byte: 1, po: 2 },
                { id: 6, label: '数据', value: '', byte: 'N', po: 'N' },
                { id: 7, label: '校验', value: '', byte: 1, po: 2 },
                { id: 8, label: '结束字节', value: '', byte: 1, po: 2 }
            ];

            const funcCodeList = {
                "82": { name: '设备请求同步时间， 获取设备充电参数', direction: '设备到平台' },
                "03": { name: '设备参数上报', direction: '设备到平台' },
                "05": { name: '刷卡请求充电', direction: '设备到平台' },
                "06": { name: '端口充电状态上报', direction: '设备到平台' },
                "07": { name: '停止充电上报', direction: '设备到平台' },
                "09": { name: '开机上报版本信息', direction: '设备到平台' },
                "0a": { name: '错误码上报', direction: '设备到平台' },
                "0b": { name: '获取新固件版本信息', direction: '设备到平台' },
                "0c": { name: '获取固件包数据', direction: '设备到平台' },
                "0e": { name: '离线订单结算', direction: '设备到平台' },
                "0f": { name: '刷卡结算订单', direction: '设备到平台' },
                "11": { name: '所有端口状态上报', direction: '设备到平台' },
                "12": { name: '设备定位上报', direction: '设备到平台' },
                "83": { name: '下发最大功率， 最小功率， 浮冲时间', direction: '平台到设备' },
                "a1": { name: '下发端口启动命令， 停止命令', direction: '平台到设备' },
                "a2": { name: '读取端口状态', direction: '平台到设备' },
                "a3": { name: '读取端口充电状态', direction: '平台到设备' },
                "f1": { name: '设备操作', direction: '平台到设备' },
                "a5": { name: '设备固件升级', direction: '平台到设备' },
                "a6": { name: '设备位置查询', direction: '平台到设备' },
                "a7": { name: '设置设备显示的二维码', direction: '平台到设备' },
                "a8": { name: '服务器查询所有端口充电状态', direction: '平台到设备' },
                "a9": { name: '服务器读取电表参数', direction: '平台到设备' },
                "84": { name: '设备请求同步时间， 获取设备充电参数', direction: '平台到设备' },
                "85": { name: '设置充电柜运行参数', direction: '平台到设备' },
                "86": { name: '读取充电柜运行参数', direction: '平台到设备' },
            };

            const list = document.getElementById('loopList');

            packetData.forEach(data => {
                const item = document.createElement('li');
                item.textContent = `${data.label}(${data.byte})======>${data.value}`;
                item.style.background = '#f5f5f5';
                list.appendChild(item);
            });

            const btn = document.getElementById('btn');
            const btnToDec = document.getElementById('btn-to-dec');
            const btnToAscii = document.getElementById('btn-to-ascii');

            btn.addEventListener('click', () => {
                const value = document.getElementById('input1-box').value.trim();
                if (!value) {
                    alert('请输入数据进行解析');
                    return;
                }
                formatProtocolData(packetData, funcCodeList, list);
            });
            btnToDec.addEventListener('click', () => {
                const value = document.getElementById('input-box2').value.trim();
                if (!value) {
                    alert('请输入数据进行转换');
                    return;
                }
                convertHexToDec();
            });
            btnToAscii.addEventListener('click', () => {
                const value = document.getElementById('input-box3').value.trim();
                if (!value) {
                    alert('请输入数据进行转换');
                    return;
                }
                convertHexToAscii();
            });
        };

        const formatProtocolData = (packetData, funcCodeList, list) => {
            let value = document.getElementById('input1-box').value.trim();
            if (!value) return;

            value = value.replace(/\s/g, '').replace(/^0x/, '');
            const arrHexStr = splitStringByTwo(value);

            packetData.forEach(v => {
                if (v.po === 'N') {
                    const len = arrHexStr.length;
                    const value = arrHexStr.splice(0, len - 2).join('');
                    const valLen = value.length;
                    v.value = `${value}(${valLen})`;
                } else {
                    const value = arrHexStr.splice(0, v.byte).join('');
                    v.value = v.label === '设备号' ? `${value}(${hexToAscii(value)})` : value;
                }
            });

            list.innerHTML = '';
            packetData.forEach(data => {
                const item = document.createElement('li');
                item.textContent = `${data.label}(${data.byte})======>` + (data.label === '功能码' ? `${data.value}(${funcCodeList[data.value].name})(${funcCodeList[data.value].direction})` : `${data.value}`);
                item.style.background = '#f5f5f5';
                list.appendChild(item);
            });
        };

        const convertHexToDec = () => {
            const value = document.getElementById('input-box2').value;
            const inputBox1Text = document.getElementById('input-box2-text');
            inputBox1Text.innerText = onHexToDec(value) || '未检测到需要转化的数据';
        };

        const convertHexToAscii = () => {
            const value = document.getElementById('input-box3').value.trim();
            if (!value) return;

            const asciiValue = hexToAscii(value);
            const inputBox3 = document.getElementById('input-box3-text');
            inputBox3.innerText = asciiValue || '未检测到需要转化的数据';
        };

        const splitStringByTwo = str => str.match(/.{1,2}/g);

        const onHexToDec = hex => hex ? parseInt(hex, 16) : null;

        const hexToAscii = hexStr => {
            if (!hexStr) return null;
            return hexStr.match(/.{1,2}/g).map(part => String.fromCharCode(parseInt(part, 16))).join('');
        };
    </script>
</body>

</html>